package com.qar.ascp;


import com.qar.annotations.myRedis;
import org.aspectj.lang.JoinPoint;
import org.aspectj.lang.ProceedingJoinPoint;
import org.aspectj.lang.Signature;
import org.aspectj.lang.annotation.Around;
import org.aspectj.lang.annotation.Aspect;
import org.aspectj.lang.reflect.MethodSignature;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.data.redis.core.RedisTemplate;
import org.springframework.expression.Expression;
import org.springframework.expression.spel.standard.SpelExpressionParser;
import org.springframework.expression.spel.support.StandardEvaluationContext;
import org.springframework.stereotype.Component;

import java.lang.reflect.Method;
import java.lang.reflect.Parameter;

@Aspect
@Component
public class Ascp {
    @Autowired
    RedisTemplate redisTemplate;

    @Around("@annotation(com.qar.annotations.myRedis)")
    public Object around(ProceedingJoinPoint joinPoint) {
        Object result = null;
        //获取方法的名字
        MethodSignature signature = (MethodSignature) joinPoint.getSignature();
        Method method = signature.getMethod();
        //判断方法上是否有这个注解
        //boolean myRedisannotationPresent = method.isAnnotationPresent(myRedis.class);
        myRedis myRedisannotation = method.getAnnotation(myRedis.class);
        //获取注解标签,对注解上的配置参数进行封装和调用
        String keyPrefix = myRedisannotation.keyPrefix();
        String matchValue = myRedisannotation.matchValue();

        //springel解析
        SpelExpressionParser spelExpressionParser = new SpelExpressionParser();
        Expression expression = spelExpressionParser.parseExpression(matchValue);
        // 创建一个StandardEvaluationContext对象，用于后续的表达式求值
        StandardEvaluationContext context = new StandardEvaluationContext();
        //利用反射获取方法参数信息
        // 获取方法的参数列表
        // 获取方法的参数值的列表
        Object[] args = joinPoint.getArgs();
        //获取方法参数的名称
        Parameter[] parameters = method.getParameters();
        for (int i = 0; i < parameters.length; i++) {
            System.out.println("获取方法里的参数名和值" + parameters[i].getName() + ":" + args[i].toString());
            // 将参数值绑定到上下文中，以便在后续处理中使用
            context.setVariable(parameters[i].getName(), args[i].toString());
        }
        //通过上诉,拼接redis的最终key
        String key = keyPrefix + ":" + expression.getValue(context).toString();
        System.out.println("最终的key是:" + key);


        //去redis中查询有没有数据
        result = redisTemplate.opsForValue().get(key);
        if (result != null) {
            System.out.println("redis中查询到了数据");
            return result;
        }
        //缓存中没有数据就从数据库中查询
        //执行业务逻辑
        try {
            result = joinPoint.proceed();
            //将数据保存到redis中
            if (result != null) {
                System.out.println("缓存没有数据,将数据库查找的结果存入redis"+result);
                redisTemplate.opsForValue().set(key, result);
            }
        } catch (Throwable e) {
            throw new RuntimeException(e);
        }
        return result;
    }
}
